home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume21 / mmv / part01 next >
Encoding:
Internet Message Format  |  1990-04-08  |  31.4 KB

  1. Subject:  v21i087:  Safely rename wildcarded files, Part01/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 179451ca bae97e21 ebca953d 10feaec3
  5.  
  6. Submitted-by: Vladimir Lanin <lanin@csd4.cs.nyu.edu>
  7. Posting-number: Volume 21, Issue 87
  8. Archive-name: mmv/part01
  9.  
  10. [  I use ren, the predecessor to mmv, all the time.  This is even
  11.    better!  --r$  ]
  12.  
  13. This is mmv, a program to move/copy/append/link multiple files according
  14. to a set of wildcard patterns.  This multiple action is performed safely,
  15. i.e., without any unexpected deletion of files due to collisions of target
  16. names with existing filenames or with other target names.  Furthermore,
  17. before doing anything, mmv attempts to detect any errors that would result
  18. from the entire set of actions specified and gives the user the choice of
  19. either aborting before beginning, or proceeding by avoiding the offending
  20. parts.
  21.  
  22. Improvements over mmv's predecessor, ren:
  23.   Support for BSD, System 5, and MS-DOS
  24.   Source and target files may (usually) reside in different directories
  25.   Paths may contain wildcards
  26.   Supports all csh wildcards: '*', '?', '['...']', and '~'
  27.   The ';' wildcard finds files at any level in the tree
  28.   Can copy, append, or link instead of moving/renaming
  29.   Reads multiple patterns from standard input (or one from command line)
  30.   No-execute option (whose output can be fed back in on standard input)
  31.  
  32. #! /bin/sh
  33. # This is a shell archive.  Remove anything before this line, then unpack
  34. # it by saving it into a file and typing "sh file".  To overwrite existing
  35. # files, type "sh file -c".  You can also feed this as standard input via
  36. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  37. # will see the following message at the end:
  38. #        "End of archive 1 (of 2)."
  39. # Contents:  MANIFEST Makefile PACKNOTES announce mmv.1 mmv.c.2
  40. # Wrapped by rsalz@litchi.bbn.com on Mon Apr  9 17:05:22 1990
  41. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  42. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  43.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  44. else
  45. echo shar: Extracting \"'MANIFEST'\" \(359 characters\)
  46. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  47. X   File Name        Archive #    Description
  48. X-----------------------------------------------------------
  49. X MANIFEST                   1    
  50. X Makefile                   1    
  51. X PACKNOTES                  1    Warnings about long lines, etc
  52. X announce                   1    
  53. X mmv.1                      1    
  54. X mmv.c.1                    2    (part 1)
  55. X mmv.c.2                    1    (part 2)
  56. END_OF_FILE
  57. if test 359 -ne `wc -c <'MANIFEST'`; then
  58.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  59. fi
  60. # end of 'MANIFEST'
  61. fi
  62. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  63.   echo shar: Will not clobber existing file \"'Makefile'\"
  64. else
  65. echo shar: Extracting \"'Makefile'\" \(281 characters\)
  66. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  67. Xall:    mmv mmv.1
  68. X
  69. Xmmv:    mmv.c
  70. X    $(CC) -o mmv $(CFLAGS) mmv.c
  71. Xinstall:    all
  72. X    @echo "Install mmv according to local convention,"
  73. X    @echo "then make links named mcp, mad, and mln to mmv."
  74. X    @echo "Under System V, edit mmv.1 to uncomment the .nr O 1 line."
  75. Xclean:
  76. X    rm -f core a.out mmv mmv.o
  77. END_OF_FILE
  78. if test 281 -ne `wc -c <'Makefile'`; then
  79.     echo shar: \"'Makefile'\" unpacked with wrong size!
  80. fi
  81. # end of 'Makefile'
  82. fi
  83. if test -f 'PACKNOTES' -a "${1}" != "-c" ; then 
  84.   echo shar: Will not clobber existing file \"'PACKNOTES'\"
  85. else
  86. echo shar: Extracting \"'PACKNOTES'\" \(82 characters\)
  87. sed "s/^X//" >'PACKNOTES' <<'END_OF_FILE'
  88. X
  89. XFile "mmv.c" was split because of its size; to create it, do
  90. X    cat mmv.c.? >mmv.c
  91. END_OF_FILE
  92. if test 82 -ne `wc -c <'PACKNOTES'`; then
  93.     echo shar: \"'PACKNOTES'\" unpacked with wrong size!
  94. fi
  95. # end of 'PACKNOTES'
  96. fi
  97. if test -f 'announce' -a "${1}" != "-c" ; then 
  98.   echo shar: Will not clobber existing file \"'announce'\"
  99. else
  100. echo shar: Extracting \"'announce'\" \(1588 characters\)
  101. sed "s/^X//" >'announce' <<'END_OF_FILE'
  102. XCopyright (c) 1989 Vladimir Lanin
  103. X
  104. XThis is mmv, a program to move/copy/append/link multiple files
  105. Xaccording to a set of wildcard patterns. This multiple action is
  106. Xperformed safely, i.e. without any unexpected deletion of files due to
  107. Xcollisions of target names with existing filenames or with other
  108. Xtarget names. Furthermore, before doing anything, mmv attempts to
  109. Xdetect any errors that would result from the entire set of actions
  110. Xspecified and gives the user the choice of either aborting before
  111. Xbeginning, or proceeding by avoiding the offending parts.
  112. X
  113. XImprovements over mmv's predecessor, ren:
  114. X
  115. X. support for BSD, System 5, and MS-DOS
  116. X
  117. X. source and target files may (usually) reside in different directories
  118. X
  119. X. paths may contain wildcards
  120. X
  121. X. supports all csh wildcards: '*', '?', '['...']', and '~'
  122. X
  123. X. the ';' wildcard finds files at any level in the tree
  124. X
  125. X. can copy, append, or link instead of moving/renaming
  126. X
  127. X. reads multiple patterns from standard input (or one from command line)
  128. X
  129. X. no-execute option (whose output can be fed back in on standard input)
  130. X
  131. XNote to users familiar with ren: the -a and -k options have been renamed
  132. Xto -t and -g, respectively, and their semantics have somewhat changed.
  133. X
  134. X
  135. XMmv is freeware. That means that the entire package of software and
  136. Xdocumentation is copyrighted, and may not be distributed with any
  137. Xmodifications or for any charge (without the author's explicit written
  138. Xpermission). Other than that, it may be used and distributed freely.
  139. X
  140. X
  141. XVladimir Lanin
  142. X330 Wadsworth Ave, Apt 6F
  143. XNew York, NY 10040
  144. X
  145. Xlanin@csd2.nyu.edu
  146. X...!cmcl2!csd2!lanin
  147. END_OF_FILE
  148. if test 1588 -ne `wc -c <'announce'`; then
  149.     echo shar: \"'announce'\" unpacked with wrong size!
  150. fi
  151. # end of 'announce'
  152. fi
  153. if test -f 'mmv.1' -a "${1}" != "-c" ; then 
  154.   echo shar: Will not clobber existing file \"'mmv.1'\"
  155. else
  156. echo shar: Extracting \"'mmv.1'\" \(17091 characters\)
  157. sed "s/^X//" >'mmv.1' <<'END_OF_FILE'
  158. X.\" Under BSD, just give to nroff or troff (with -man).
  159. X.\" To print the MS-DOS version, use option -rO2.
  160. X.\" Under System V, take out the '.\"  ' from the next line.
  161. X.\" .nr O 1
  162. X.TH MMV 1 "November 20, 1989 (v1.0)"
  163. X.ie !'\nO'2' \{\
  164. X.SH NAME
  165. Xmmv \- move/copy/append/link multiple files by wildcard patterns
  166. X\}
  167. X.el \{
  168. X.SH NAME
  169. Xmmv \- move/copy/append multiple files by wildcard patterns
  170. X\}
  171. X.ie '\nO'2' \{\
  172. X.ds SL \\\\
  173. X.ds ES '
  174. X\}
  175. X.el \{\
  176. X.ds SL /
  177. X.ds ES \\\\
  178. X\}
  179. X.SH SYNOPSIS
  180. X.B mmv
  181. X.if '\nO'2' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBz\fP]
  182. X.if '\nO'0' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBl\fP|\fBs\fP]
  183. X.if '\nO'1' [\fB-m\fP|\fBx\fP|\fBr\fP|\fBc\fP|\fBo\fP|\fBa\fP|\fBl\fP]
  184. X[\fB-h\fP]
  185. X[\fB-d\fP|\fBp\fP]
  186. X[\fB-g\fP|\fBt\fP]
  187. X[\fB-v\fP|\fBn\fP]
  188. X[\fBfrom to\fP]
  189. X.if '\nO'2' \{\
  190. X.br
  191. X.B mmvpatch
  192. X[\fBexecutable\fP]
  193. X\}
  194. X.SH "DESCRIPTION"
  195. X.I Mmv
  196. Xmoves (or copies,
  197. X.ie '\nO'2' or appends,
  198. X.el appends, or links,
  199. Xas specified)
  200. Xeach source file matching a
  201. X.I from
  202. Xpattern to the target name specified by the
  203. X.I to
  204. Xpattern.
  205. XThis multiple action is performed safely,
  206. Xi.e. without any unexpected deletion of files
  207. Xdue to collisions of target names with existing filenames
  208. Xor with other target names.
  209. XFurthermore, before doing anything,
  210. X.I mmv
  211. Xattempts to detect any errors that would result
  212. Xfrom the entire set of actions specified
  213. Xand gives the user the choice of either
  214. Xproceeding by avoiding the offending parts
  215. Xor aborting.
  216. X
  217. X.ce
  218. XThe Task Options
  219. X.PP
  220. XWhether
  221. X.I mmv
  222. Xmoves, copies,
  223. X.ie '\nO'2' or appends
  224. X.el appends, or links
  225. Xis governed by the first set of options given
  226. Xabove.
  227. XIf none of these are specified,
  228. X.ie '\nO'2' \{\
  229. Xa default (patchable by
  230. X.IR mmvpatch ,
  231. Xand initially -x)
  232. Xdetermines the task.
  233. X\}
  234. X.el \{\
  235. Xthe task is given by the command name under which
  236. X.I mmv
  237. Xwas invoked (argv[0]):
  238. X
  239. X    command name    default task
  240. X
  241. X    mmv            -x
  242. X.br
  243. X    mcp            -c
  244. X.br
  245. X    mad            -a
  246. X.br
  247. X    mln            -l
  248. X\}
  249. X.PP
  250. XThe task option choices are:
  251. X.TP
  252. X-m :
  253. Xmove source file to target name.
  254. XBoth must be on the same device.
  255. XWill not move directories.
  256. X.if '\nO'0' \{\
  257. XIf the source file is a symbolic link,
  258. Xmoves the link without checking if the link's target from the new
  259. Xdirectory is different than the old.
  260. X\}
  261. X.TP
  262. X-x :
  263. Xsame as -m, except cross-device moves are done
  264. Xby copying, then deleting source.
  265. XWhen copying, sets the
  266. X.ie !'\nO'2' permission bits
  267. X.el attributes
  268. Xand file modification time
  269. Xof the target file to that of the source file.
  270. X.TP
  271. X-r :
  272. Xrename source file or directory to target name.
  273. XThe target name must not include a path:
  274. Xthe file remains in the same directory in all cases.
  275. XThis option is the only way of renaming directories under
  276. X.IR mmv .
  277. X.if '\nO'2' It is only available under DOS version 3.0 or higher.
  278. X.TP
  279. X-c :
  280. Xcopy source file to target name.
  281. XSets the file modification time and
  282. X.ie !'\nO'2' permission bits
  283. X.el attributes
  284. Xof the target file to that of the source file,
  285. Xregardless of whether the target file already exists.
  286. XChains and cycles (to be explained below) are not allowed.
  287. X.TP
  288. X-o :
  289. Xoverwrite target name with source file.
  290. X.ie '\nO'2' \{\
  291. XIf target file exists, its attributes are left unchanged.
  292. XIf not, it is created with ordinary attributes
  293. Xunrelated to the source file's attributes.
  294. XIn either case, the file modification time is set to the current time.
  295. X\}
  296. X.el \{\
  297. XIf target file exists, it is overwritten,
  298. Xkeeping its original owner and permission bits.
  299. XIf it does not exist, it is created, with read-write permission bits
  300. Xset according to
  301. X.IR umask (1),
  302. Xand the execute permission bits copied from the source file.
  303. XIn either case, the file modification time is set to the current time.
  304. X\}
  305. X.TP
  306. X-a :
  307. Xappend contents of source file to target name.
  308. XTarget file modification time is set to the current time.
  309. XIf target file does not exist,
  310. Xit is created with
  311. X.ie '\nO'2' attributes
  312. X.el permission bits
  313. Xset as under -o.
  314. XUnlike all other options, -a allows multiple source files to have the
  315. Xsame target name, e.g. "mmv -a
  316. X.ie '\nO'2' *.c
  317. X.el \\*.c
  318. Xbig" will append all ".c" files to "big".
  319. XChains and cycles are also allowed, so "mmv -a f f" will double up "f".
  320. X.ie '\nO'2' \{\
  321. X.TP
  322. X-z :
  323. Xsame as -a, but if the target file exists, and its last character is a ^Z,
  324. Xand the source file is not empty,
  325. Xthis ^Z is truncated before doing the append.
  326. X\}
  327. X.el \{\
  328. X.TP
  329. X-l :
  330. Xlink target name to source file.
  331. XBoth must be on the same device,
  332. Xand the source must not be a directory.
  333. XChains and cycles are not allowed.
  334. X.if '\nO'0' \{\
  335. X.TP
  336. X-s :
  337. Xsame as -l, but use symbolic links instead of hard links.
  338. XFor the resulting link to aim back at the source,
  339. Xeither the source name must begin with a '/',
  340. Xor the target must reside in either the current or the source directory.
  341. XIf none of these conditions are met, the link is refused.
  342. XHowever, source and target can reside on different devices,
  343. Xand the source can be a directory.
  344. X\}
  345. X\}
  346. X.PP
  347. XOnly one of these option may be given,
  348. Xand it applies to all matching files.
  349. XRemaining options need not be given separately,
  350. Xi.e. "mmv -mk" is allowed.
  351. X
  352. X.ce
  353. XMultiple Pattern Pairs
  354. X.PP
  355. XMultiple
  356. X.I from
  357. X--
  358. X.I to
  359. Xpattern pairs may be specified by omitting
  360. Xthe pattern pair on the command line,
  361. Xand entering them on the standard input,
  362. Xone pair per line.
  363. X(If a pattern pair is given on the command line,
  364. Xthe standard input is not read.)
  365. XThus,
  366. X
  367. X.in +3
  368. Xmmv
  369. X.br
  370. Xa b
  371. X.br
  372. Xc d
  373. X.in -3
  374. X
  375. Xwould rename "a" to "b" and "c" to "d".
  376. XIf a file can be matched to several of the given
  377. X.I from
  378. Xpatterns,
  379. Xthe
  380. X.I to
  381. Xpattern of the first matching pair is used.
  382. XThus,
  383. X
  384. X.in +3
  385. Xmmv
  386. X.br
  387. Xa b
  388. X.br
  389. Xa c
  390. X.in -3
  391. X
  392. Xwould give the error message "a -> c : no match" because file "a"
  393. X(even if it exists)
  394. Xwas already matched by the first pattern pair.
  395. X
  396. X.ce
  397. XThe \fIFrom\fP Pattern
  398. X.PP
  399. XThe
  400. X.I from
  401. Xpattern is a filename
  402. Xwith embedded wildcards: '*', '?', '['...']',
  403. X.if '\nO'2' \{\
  404. X\'!',
  405. X\}
  406. Xand ';'.
  407. XThe first three have their usual
  408. X.IR sh (1)
  409. Xmeanings of, respectively,
  410. Xmatching any string of characters,
  411. Xmatching any single character,
  412. Xand matching any one of a set of characters.
  413. X.PP
  414. XBetween the '[' and ']', a range from character 'a' through character 'z'
  415. Xis specified with "a-z".
  416. XThe set of matching characters can be negated by inserting
  417. Xa '^' after the '['.
  418. XThus, "[^b-e2-5_]"
  419. Xwill match any character but 'b' through 'e', '2' through '5', and '_'.
  420. X.if '\nO'2' \{\
  421. X.PP
  422. XUnlike DOS wildcards,
  423. Xall mmv wildcards (except for cases listed below)
  424. Xcan occur anywhere in the pattern,
  425. Xwhether preceding or following explicit characters or other wildcards.
  426. XFor example, the pattern "*z\\foo.bar" will search
  427. Xfor files named "foo.bar" in all subdirectories whose names end in 'z'.
  428. XHowever, no wildcards can occur in the drive letter.
  429. X.PP
  430. XThe character '.' is not matched by any of '*', '?', or '['...']'.
  431. XThus, the pattern "*" will only match files with a null extension.
  432. XTo save yourself some typing, use the '!' wildcard instead,
  433. Xwhich matches the same as "*.*",
  434. Xexcept it is assigned only one wildcard index (see below).
  435. XThus, both "f!" and "f*.*"
  436. Xwill match all of "f", "f.ext", "foo", and "foo.ext",
  437. Xwhile "f*" will match only the first and the third.
  438. X\}
  439. X.PP
  440. XNote that paths are allowed in the patterns,
  441. Xand wildcards may be intermingled with slashes arbitrarily.
  442. XThe ';' wildcard
  443. Xis useful for matching files at any depth in the directory tree.
  444. XIt matches the same as "*\*(SL" repeated any number of times, including zero,
  445. Xand can only occur either at the beginning of the pattern
  446. Xor following a '\*(SL'.
  447. XThus ";*.c" will match all ".c" files in or below the current directory,
  448. Xwhile "\*(SL;*.c" will match them anywhere on the file system.
  449. X.if !'\nO'2' \{\
  450. X.PP
  451. XIn addition, if the
  452. X.I from
  453. Xpattern
  454. X(or the
  455. X.I to
  456. Xpattern)
  457. Xbegins with "~/", the '~' is replaced with the home directory name.
  458. X(Note that the "~user" feature of
  459. X.IR csh (1)
  460. Xis not implemented.)
  461. XHowever, the '~' is not treated as a wildcard,
  462. Xin the sense that it is not assigned a wildcard index (see below).
  463. X\}
  464. X.PP
  465. XSince matching a directory under a task option other than -r or -s
  466. Xwould result in an error,
  467. Xtasks other than -r and -s
  468. Xmatch directories only against completely explicit
  469. X.I from
  470. Xpatterns (i.e. not containing wildcards).
  471. XUnder -r and -s, this applies only to "." and "..".
  472. X.PP
  473. X.ie '\nO'2' \{\
  474. XHidden and system files are also only matched
  475. Xagainst completely explicit
  476. X.I from
  477. Xpatterns.
  478. X\}
  479. X.el \{\
  480. XFiles beginning with '.' are only matched against
  481. X.I from
  482. Xpatterns that begin with an explicit '.'.
  483. X\}
  484. XHowever, if -h is specified, they are matched normally.
  485. X.if !'\nO'2' \{\
  486. X.PP
  487. XWarning: since the shell normally expands wildcards
  488. Xbefore passing the command-line arguments to
  489. X.IR mmv ,
  490. Xit is usually necessary to enclose the command-line
  491. X.I from
  492. Xpattern
  493. Xin quotes.
  494. X\}
  495. X
  496. X.ce
  497. XThe \fITo\fP Pattern
  498. X.PP
  499. XThe
  500. X.I to
  501. Xpattern is a filename
  502. Xwith embedded
  503. X.I wildcard
  504. X.IR indexes ,
  505. Xwhere an index consists of the character '='
  506. Xfollowed by a string of digits.
  507. XWhen a source file matches a
  508. X.I from
  509. Xpattern,
  510. Xa target name for the file is constructed out of the
  511. X.I to
  512. Xpattern by
  513. Xreplacing the wildcard indexes by the
  514. Xactual characters that matched the referenced wildcards
  515. Xin the source name.
  516. XThus, if the
  517. X.I from
  518. Xpattern is "abc*.*" and the
  519. X.I to
  520. Xpattern is "xyz=2.=1",
  521. Xthen "abc.txt" is targeted to "xyztxt.".
  522. X(The first '*' matched "", and the second matched "txt".)
  523. XSimilarly, for the pattern pair ";*.[clp]" -> "=1=3\*(SL=2",
  524. X"foo1\*(SLfoo2\*(SLprog.c" is targeted to "foo1\*(SLfoo2\*(SLc\*(SLprog".
  525. XNote that there is no '\*(SL' following the "=1" in the
  526. X.I to
  527. Xpattern,
  528. Xsince the string matched by any ';' is always either empty
  529. Xor ends in a '\*(SL'.
  530. XIn this case, it matches "foo1\*(SLfoo2\*(SL".
  531. X.if !'\nO'2' \{\
  532. X.PP
  533. XTo convert the string matched by a wildcard
  534. Xto either lowercase or uppercase before embedding it in the target name,
  535. Xinsert 'l' or 'u', respectively,
  536. Xbetween the '=' and the string of digits.
  537. X.PP
  538. XThe
  539. X.I to
  540. Xpattern,
  541. Xlike the
  542. X.I from
  543. Xpattern,
  544. Xcan begin with a "~/" (see above).
  545. XThis does not necessitate enclosing the
  546. X.I to
  547. Xpattern in quotes on the command line
  548. Xsince
  549. X.IR csh (1)
  550. Xexpands the '~' in the exact same manner as
  551. X.I mmv
  552. X(or, in the case of
  553. X.IR sh (1),
  554. Xdoes not expand it at all).
  555. X\}
  556. X.PP
  557. XFor all task options other than -r, if the target name is a directory,
  558. Xthe real target name is formed by appending
  559. Xa '\*(SL' followed by the last component
  560. Xof the source file name.
  561. XFor example, "mmv dir1\*(SLa dir2" will,
  562. Xif "dir2" is indeed a directory, actually move "dir1\*(SLa" to "dir2\*(SLa".
  563. XHowever, if "dir2\*(SLa" already exists and is itself a directory,
  564. Xthis is considered an error.
  565. X.PP
  566. XTo strip any character (e.g. '*', '?', or '=')
  567. Xof its special meaning to
  568. X.IR mmv ,
  569. Xas when the actual replacement name must contain the character '=',
  570. Xprecede the special character with a
  571. X.ie '\nO'2' \{\
  572. Xsingle quote (').
  573. X\}
  574. X.el \{\
  575. X\'\\'
  576. X(and enclose the argument in quotes because of the shell).
  577. X\}
  578. XThis also works to terminate a wildcard index
  579. Xwhen it has to be followed by a digit in the filename, e.g. "a=1\*(ES1".
  580. X
  581. X.ce
  582. XChains and Cycles
  583. X.PP
  584. XA chain is a sequence of specified actions where the target name of
  585. Xone action refers to the source file of another action.
  586. XFor example,
  587. X
  588. Xmmv
  589. X.br
  590. Xa b
  591. X.br
  592. Xb c
  593. X
  594. Xspecifies the chain "a" -> "b" -> "c".
  595. XA cycle is a chain where the last target name
  596. Xrefers back to the first source file,
  597. Xe.g. "mmv a a".
  598. X.I Mmv
  599. Xdetects chains and cycles regardless of the order in which
  600. Xtheir constituent actions are actually given.
  601. XWhere allowed, i.e. in moving, renaming, and appending files,
  602. Xchains and cycles are handled gracefully, by performing them in the proper
  603. Xorder.
  604. XCycles are broken by first renaming one of the files to a temporary name
  605. X(or just remembering its original size when doing appends).
  606. X
  607. X.ce
  608. XCollisions and Deletions
  609. X.PP
  610. XWhen any two or more matching files
  611. Xwould have to be
  612. X.ie '\nO'2' moved or copied
  613. X.el moved, copied, or linked
  614. Xto the same target filename,
  615. X.I mmv
  616. Xdetects the condition as an error before performing any actions.
  617. XFurthermore,
  618. X.I mmv
  619. Xchecks if any of its actions will result
  620. Xin the destruction of existing files.
  621. XIf the -d (delete) option is specified,
  622. Xall file deletions or overwrites are done silently.
  623. XUnder -p (protect), all deletions or overwrites
  624. X(except those specified with "(*)" on the standard input, see below)
  625. Xare treated as errors.
  626. XAnd if neither option is specified,
  627. Xthe user is queried about each deletion or overwrite separately.
  628. X(A new stream to
  629. X.ie '\nO'2' "\\dev\\con"
  630. X.el "/dev/tty"
  631. Xis used for all interactive queries,
  632. Xnot the standard input.)
  633. X
  634. X.ce
  635. XError Handling
  636. X.PP
  637. XWhenever any error in the user's action specifications is detected,
  638. Xan error message is given on the standard output,
  639. Xand
  640. X.I mmv
  641. Xproceeds to check the rest of the specified actions.
  642. XOnce all errors are detected,
  643. X.I mmv
  644. Xqueries the user whether he wishes
  645. Xto continue by avoiding the erroneous actions or to abort altogether.
  646. XThis and all other queries may be avoided by specifying either the
  647. X-g (go) or -t (terminate) option.
  648. XThe former will resolve all difficulties by avoiding the erroneous actions;
  649. Xthe latter will abort
  650. X.I mmv
  651. Xif any errors are detected.
  652. XSpecifying either of them defaults
  653. X.I mmv
  654. Xto -p, unless -d is specified
  655. X(see above).
  656. XThus, -g and -t are most useful when running
  657. X.I mmv
  658. Xin the background or in
  659. Xa shell script,
  660. Xwhen interactive queries are undesirable.
  661. X
  662. X.ce
  663. XReports
  664. X.PP
  665. XOnce the actions to be performed are determined,
  666. X.I mmv
  667. Xperforms them silently,
  668. Xunless either the -v (verbose) or -n (no-execute) option is specified.
  669. XThe former causes
  670. X.I mmv
  671. Xto report each performed action
  672. Xon the standard output as
  673. X
  674. Xa -> b : done.
  675. X
  676. XHere, "a" and "b" would be replaced by the source and target names,
  677. Xrespectively.
  678. XIf the action deletes the old target,
  679. Xa "(*)" is inserted after the the target name.
  680. XAlso, the "->" symbol is modified when a cycle has to be broken:
  681. Xthe '>' is changed to a '^' on the action prior to which the old target
  682. Xis renamed to a temporary,
  683. Xand the '-' is changed to a '=' on the action where the temporary is used.
  684. X.PP
  685. XUnder -n, none of the actions are performed,
  686. Xbut messages like the above are printed on the standard output
  687. Xwith the ": done." omitted.
  688. X.PP
  689. XThe output generated by -n can (after editing, if desired)
  690. Xbe fed back to
  691. X.I mmv
  692. Xon the standard input
  693. X(by omitting the
  694. X.I from
  695. X--
  696. X.I to
  697. Xpair on the
  698. X.I mmv
  699. Xcommand line).
  700. XTo facilitate this,
  701. X.I mmv
  702. Xignores lines on the standard input that look
  703. Xlike its own error and "done" messages,
  704. Xas well as all lines beginning with white space,
  705. Xand will accept pattern pairs with or without the intervening "->"
  706. X(or "-^", "=>", or "=^").
  707. XLines with "(*)" after the target pattern have the effect of enabling -d
  708. Xfor the files matching this pattern only,
  709. Xso that such deletions are done silently.
  710. XWhen feeding
  711. X.I mmv
  712. Xits own output,
  713. Xone must remember to specify again the task option (if any)
  714. Xoriginally used to generate it.
  715. X.PP
  716. XAlthough
  717. X.I mmv
  718. Xattempts to predict all mishaps prior to performing any specified actions,
  719. Xaccidents may happen.
  720. XFor example,
  721. X.I mmv
  722. Xdoes not check for adequate free space when copying.
  723. XThus, despite all efforts,
  724. Xit is still possible for an action to fail
  725. Xafter some others have already been done.
  726. XTo make recovery as easy as possible,
  727. X.I mmv
  728. Xreports which actions have already been done and
  729. Xwhich are still to be performed
  730. Xafter such a failure occurs.
  731. XIt then aborts, not attempting to do anything else.
  732. XOnce the user has cleared up the problem,
  733. Xhe can feed this report back to
  734. X.I mmv
  735. Xon the standard input
  736. Xto have it complete the task.
  737. X(The user is queried for a file name to dump this report
  738. Xif the standard output has not been redirected.)
  739. X.if '\nO'2' \{\
  740. X
  741. X.ce
  742. X\fIMmvpatch\fP
  743. X.PP
  744. XYou can customize a copy of
  745. X.I mmv
  746. Xvia the
  747. X.I mmvpatch
  748. Xutility.
  749. XIf you wish to change the default task option,
  750. Xrun
  751. X.I mmvpatch
  752. Xon a copy of
  753. X.I mmv
  754. Xnamed as follows:
  755. X
  756. X    -x, -m, -r        mmv.exe
  757. X.br
  758. X    -c, -o            mcp.exe
  759. X.br
  760. X    -a, -z            mad.exe
  761. X.PP
  762. X.I Mmvpatch
  763. Xalso determines the best way to uniquely identify directories.
  764. XAs distributed,
  765. X.I mmv
  766. Xis set to use a method that is guaranteed to work the same way
  767. Xfor all versions of DOS,
  768. Xbut is both slow
  769. Xand unable to correctly handle drives
  770. Xaffected by the
  771. X.I join
  772. Xand
  773. X.I subst
  774. XDOS commands.
  775. XAlternatively,
  776. Xthere is a method that is fast and correct,
  777. Xbut uses an undocumented DOS feature
  778. Xthat may not work properly under all versions of DOS.
  779. X(However, 2.0 and 3.3 are known to work.)
  780. X.I Mmv
  781. Xdoes
  782. X.I not
  783. Xdetermine the best method to use on your system
  784. Xat run-time since this is too slow.
  785. XThe choice is left to
  786. X.I mmvpatch,
  787. Xwhich determines if the fast method works,
  788. Xbut also allows you to return to the slow method.
  789. X\}
  790. X.SH "EXIT STATUS"
  791. X.I Mmv
  792. Xexits with status 1 if it aborts before doing anything,
  793. Xwith status 2 if it aborts due to failure after completing some of the
  794. Xactions,
  795. Xand with status 0 otherwise.
  796. X.if !'\nO'2' \{\
  797. X.SH "SEE ALSO"
  798. Xmv(1), cp(1), ln(1), umask(1)
  799. X\}
  800. X.SH "AUTHOR"
  801. XVladimir Lanin
  802. X.br
  803. Xlanin@csd2.nyu.edu
  804. X.SH "BUGS"
  805. X.if !'\nO'2' \{\
  806. XIf the search pattern is not quoted,
  807. Xthe shell expands the wildcards.
  808. X.I Mmv
  809. Xthen (usually) gives some error message,
  810. Xbut can not determine that the lack of quotes is the cause.
  811. X.PP
  812. X\}\
  813. XTo avoid difficulties in semantics and error checking,
  814. X.I mmv
  815. Xrefuses to move or create directories.
  816. END_OF_FILE
  817. if test 17091 -ne `wc -c <'mmv.1'`; then
  818.     echo shar: \"'mmv.1'\" unpacked with wrong size!
  819. fi
  820. # end of 'mmv.1'
  821. fi
  822. if test -f 'mmv.c.2' -a "${1}" != "-c" ; then 
  823.   echo shar: Will not clobber existing file \"'mmv.c.2'\"
  824. else
  825. echo shar: Extracting \"'mmv.c.2'\" \(7214 characters\)
  826. sed "s/^X//" >'mmv.c.2' <<'END_OF_FILE'
  827. Xstatic int movealias(first, p, pprintaliased)
  828. X    REP *first, *p;
  829. X    int *pprintaliased;
  830. X{
  831. X    char *fstart;
  832. X    int ret;
  833. X
  834. X    strcpy(pathbuf, p->r_hto->h_name);
  835. X    fstart = pathbuf + strlen(pathbuf);
  836. X    strcpy(fstart, TEMP);
  837. X    for (
  838. X        ret = 0;
  839. X        sprintf(fstart + STRLEN(TEMP), "%03d", ret),
  840. X        fsearch(fstart, p->r_hto->h_di) != NULL;
  841. X        ret++
  842. X    )
  843. X        ;
  844. X    if (rename(fullrep, pathbuf)) {
  845. X        fprintf(stderr,
  846. X            "%s -> %s has failed.\n", fullrep, pathbuf);
  847. X        *pprintaliased = snap(first, p);
  848. X    }
  849. X    return(ret);
  850. X}
  851. X
  852. X
  853. Xstatic int snap(first, p)
  854. X    REP *first, *p;
  855. X{
  856. X    char fname[80];
  857. X    int redirected = 0;
  858. X
  859. X    if (noex)
  860. X        exit(1);
  861. X
  862. X    failed = 1;
  863. X#ifdef MSDOS
  864. X    ctrlbrk((int (*)())breakstat);
  865. X#else
  866. X    signal(SIGINT, breakstat);
  867. X#endif
  868. X    if (
  869. X        badstyle == ASKBAD &&
  870. X        isatty(fileno(stdout)) &&
  871. X        getreply("Redirect standard output to file? ", 0)
  872. X    ) {
  873. X        redirected = 1;
  874. X#ifndef MSDOS
  875. X        umask(oldumask);
  876. X#endif
  877. X        while (
  878. X            fprintf(stderr, "File name> "),
  879. X            (outfile = fopen(gets(fname), "w")) == NULL
  880. X        )
  881. X            fprintf(stderr, "Can't open %s.\n", fname);
  882. X    }
  883. X    if (redirected || !verbose)
  884. X        showdone(p);
  885. X    fprintf(outfile, "The following left undone:\n");
  886. X    noex = 1;
  887. X    return(first != p);
  888. X}
  889. X
  890. X
  891. Xstatic void showdone(fin)
  892. X    REP *fin;
  893. X{
  894. X    REP *first, *p;
  895. X
  896. X    for (first = hrep.r_next; ; first = first->r_next)
  897. X        for (p = first; p != NULL; p = p->r_thendo) {
  898. X            if (p == fin)
  899. X                return;
  900. X            fprintf(outfile, "%s%s %c%c %s%s : done%s\n",
  901. X                p->r_hfrom->h_name, p->r_ffrom->fi_name,
  902. X                p->r_flags & R_ISALIASED ? '=' : '-',
  903. X                p->r_flags & R_ISCYCLE ? '^' : '>',
  904. X                p->r_hto->h_name, p->r_nto,
  905. X                (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "");
  906. X        }
  907. X}
  908. X
  909. X
  910. Xstatic void breakout()
  911. X{
  912. X    fflush(stdout);
  913. X    fprintf(stderr, "Aborting, nothing done.\n");
  914. X    exit(1);
  915. X}
  916. X
  917. X
  918. Xstatic int breakrep()
  919. X{
  920. X    gotsig = 1;
  921. X    return(1);
  922. X}
  923. X
  924. X
  925. Xstatic void breakstat()
  926. X{
  927. X    exit(1);
  928. X}
  929. X
  930. X
  931. Xstatic void quit()
  932. X{
  933. X    fprintf(stderr, "Aborting, nothing done.\n");
  934. X    exit(1);
  935. X}
  936. X
  937. X
  938. Xstatic int copymove(p)
  939. X    REP *p;
  940. X{
  941. X#ifndef MSDOS
  942. X#ifndef SYSV
  943. X    {
  944. X        int llen;
  945. X        char linkbuf[MAXPATH];
  946. X
  947. X        if ((llen = readlink(pathbuf, linkbuf, MAXPATH - 1)) != 1) {
  948. X            linkbuf[llen] = '\0';
  949. X            return(symlink(linkbuf, fullrep) || myunlink(pathbuf, p->r_ffrom));
  950. X        }
  951. X    }
  952. X#endif
  953. X#endif
  954. X    return(copy(p->r_ffrom, -1) || myunlink(pathbuf, p->r_ffrom));
  955. X}
  956. X
  957. X
  958. X
  959. X#define IRWMASK (S_IREAD | S_IWRITE)
  960. X#define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6))
  961. X
  962. Xstatic int copy(ff, len)
  963. X    FILEINFO *ff;
  964. X    long len;
  965. X{
  966. X    char buf[BUFSIZE], c;
  967. X    int f, t, k, mode, perm;
  968. X#ifdef MSDOS
  969. X    struct ftime tim;
  970. X#else
  971. X#ifdef SYSV
  972. X    struct utimbuf tim;
  973. X#else
  974. X    struct timeval tim[2];
  975. X#endif
  976. X    struct stat fstat;
  977. X#endif
  978. X
  979. X    if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0)
  980. X        return(-1);
  981. X    perm =
  982. X#ifdef MSDOS
  983. X        IRWMASK        /* will _chmod it later (to get all the attributes) */
  984. X#else
  985. X        (op & (APPEND | OVERWRITE)) ?
  986. X            (~oldumask & RWMASK) | (ff->fi_mode & ~RWMASK) :
  987. X            ff->fi_mode
  988. X#endif
  989. X        ;
  990. X    mode = O_CREAT |
  991. X#ifdef MSDOS
  992. X        O_BINARY | (op & ZAPPEND ? O_RDWR : O_WRONLY)
  993. X#else
  994. X        O_WRONLY
  995. X#endif
  996. X        ;
  997. X    if (!(op & APPEND))
  998. X        mode |= O_TRUNC;
  999. X    if ((t = open(fullrep, mode, perm)) < 0) {
  1000. X        close(f);
  1001. X        return(-1);
  1002. X    }
  1003. X    if (op & APPEND)
  1004. X        lseek(t, 0, 2);
  1005. X#ifdef MSDOS
  1006. X    if (op & ZAPPEND && filelength(t) != 0) {
  1007. X        if (lseek(t, -1, 1) == -1L || read(t, &c, 1) != 1) {
  1008. X            close(f);
  1009. X            close(t);
  1010. X            return(-1);
  1011. X        }
  1012. X        if (c == 26)
  1013. X            lseek(t, -1, 1);
  1014. X    }
  1015. X#endif
  1016. X    if ((op & APPEND) && len != -1L) {
  1017. X        while (
  1018. X            len != 0 &&
  1019. X            (k = read(f, buf, len > BUFSIZE ? BUFSIZE : (unsigned)len)) > 0 &&
  1020. X            write(t, buf, k) == k
  1021. X        )
  1022. X            len -= k;
  1023. X        if (len == 0)
  1024. X            k = 0;
  1025. X    }
  1026. X    else 
  1027. X        while ((k = read(f, buf, BUFSIZE)) > 0 && write(t, buf, k) == k)
  1028. X            ;
  1029. X    if (!(op & (APPEND | OVERWRITE)))
  1030. X        if (
  1031. X#ifdef MSDOS
  1032. X            getftime(f, &tim) ||
  1033. X            setftime(t, &tim) ||
  1034. X            _chmod(fullrep, 1, ff->fi_attrib) == -1
  1035. X#else
  1036. X            stat(pathbuf, &fstat) ||
  1037. X            (
  1038. X#ifdef SYSV
  1039. X                tim.actime = fstat.st_atime,
  1040. X                tim.modtime = fstat.st_mtime,
  1041. X#else
  1042. X                tim[0].tv_sec = fstat.st_atime,
  1043. X                tim[1].tv_sec = fstat.st_mtime,
  1044. X#endif
  1045. X                utimes(fullrep, tim)
  1046. X            )
  1047. X#endif
  1048. X        )
  1049. X            fprintf(stderr, "Strange, couldn't transfer time from %s to %s.\n",
  1050. X                pathbuf, fullrep);
  1051. X
  1052. X    close(f);
  1053. X    close(t);
  1054. X    if (k != 0) {
  1055. X        if (!(op & APPEND))
  1056. X            unlink(fullrep);
  1057. X        return(-1);
  1058. X    }
  1059. X    return(0);
  1060. X}
  1061. X
  1062. X
  1063. X#ifndef RENAME
  1064. Xstatic int rename(from, to)
  1065. X    char *from, *to;
  1066. X{
  1067. X    if (link(from, to))
  1068. X        return(-1);
  1069. X    if (unlink(from)) {
  1070. X        unlink(to);
  1071. X        return(-1);
  1072. X    }
  1073. X    return(0);
  1074. X}
  1075. X#endif
  1076. X
  1077. X
  1078. Xstatic int myunlink(n, f)
  1079. X    char *n;
  1080. X    FILEINFO *f;
  1081. X{
  1082. X#ifdef MSDOS
  1083. X    int a;
  1084. X
  1085. X    if (((a = f->fi_attrib) & FA_RDONLY) && _chmod(n, 1, a & ~FA_RDONLY) < 0) {
  1086. X        fprintf(stderr, "Strange, can not _chmod (or unlink) %s.\n", f);
  1087. X        return(-1);
  1088. X    }
  1089. X#endif
  1090. X    if (unlink(n)) {
  1091. X        fprintf(stderr, "Strange, can not unlink %s.\n", n);
  1092. X        return(-1);
  1093. X    }
  1094. X    return(0);
  1095. X}
  1096. X
  1097. X
  1098. Xstatic int getreply(m, failact)
  1099. X    char *m;
  1100. X    int failact;
  1101. X{
  1102. X    static FILE *tty = NULL;
  1103. X    int c, r;
  1104. X
  1105. X    fprintf(stderr, m);
  1106. X    if (tty == NULL && (tty = fopen(TTY, "r")) == NULL) {
  1107. X        fprintf(stderr, "Can not open %s to get reply.\n", TTY);
  1108. X        if (failact == -1)
  1109. X            quit();
  1110. X        else
  1111. X            return(failact);
  1112. X    }
  1113. X    for (;;) {
  1114. X        r = fgetc(tty);
  1115. X        if (r == EOF) {
  1116. X            fprintf(stderr, "Can not get reply.\n");
  1117. X            if (failact == -1)
  1118. X                quit();
  1119. X            else
  1120. X                return(failact);
  1121. X        }
  1122. X        if (r != '\n')
  1123. X            while ((c = fgetc(tty)) != '\n' && c != EOF)
  1124. X                ;
  1125. X        r = mylower(r);
  1126. X        if (r == 'y' || r == 'n')
  1127. X            return(r == 'y');
  1128. X        fprintf(stderr, "Yes or No? ");
  1129. X    }
  1130. X}
  1131. X
  1132. X
  1133. Xstatic void *myalloc(k)
  1134. X    unsigned k;
  1135. X{
  1136. X    void *ret;
  1137. X
  1138. X    if (k == 0)
  1139. X        return(NULL);
  1140. X    if ((ret = (void *)malloc(k)) == NULL) {
  1141. X        fprintf(stderr, "Insufficient memory.\n");
  1142. X        quit();
  1143. X    }
  1144. X    return(ret);
  1145. X}
  1146. X
  1147. X
  1148. Xstatic void *challoc(k, which)
  1149. X    int which;
  1150. X    int k;
  1151. X{
  1152. X    void *ret;
  1153. X    CHUNK *p, *q;
  1154. X    SLICER *sl = &(slicer[which]);
  1155. X
  1156. X    if (k > sl->sl_len) {
  1157. X        for (
  1158. X            q = NULL, p = freechunks;
  1159. X            p != NULL && (sl->sl_len = p->ch_len) < k;
  1160. X            q = p, p = p->ch_next
  1161. X        )
  1162. X            ;
  1163. X        if (p == NULL) {
  1164. X            sl->sl_len = CHUNKSIZE - sizeof(CHUNK *);
  1165. X            p = (CHUNK *)myalloc(CHUNKSIZE);
  1166. X        }
  1167. X        else if (q == NULL)
  1168. X            freechunks = p->ch_next;
  1169. X        else
  1170. X            q->ch_next = p->ch_next;
  1171. X        p->ch_next = sl->sl_first;
  1172. X        sl->sl_first = p;
  1173. X        sl->sl_unused = (char *)&(p->ch_len);
  1174. X    }
  1175. X    sl->sl_len -= k;
  1176. X    ret = (void *)sl->sl_unused;
  1177. X    sl->sl_unused += k;
  1178. X    return(ret);
  1179. X}
  1180. X
  1181. X
  1182. Xstatic void chgive(p, k)
  1183. X    void *p;
  1184. X    unsigned k;
  1185. X{
  1186. X    ((CHUNK *)p)->ch_len = k - sizeof(CHUNK *);
  1187. X    ((CHUNK *)p)->ch_next = freechunks;
  1188. X    freechunks = (CHUNK *)p;
  1189. X}
  1190. X
  1191. X
  1192. X#ifndef MSDOS
  1193. Xstatic void memmove(to, from, k)
  1194. X    char *to, *from;
  1195. X    unsigned k;
  1196. X{
  1197. X    if (from > to)
  1198. X        while (k-- != 0)
  1199. X            *(to++) = *(from++);
  1200. X    else {
  1201. X        from += k;
  1202. X        to += k;
  1203. X        while (k-- != 0)
  1204. X            *(--to) = *(--from);
  1205. X    }
  1206. X}
  1207. X#endif
  1208. X
  1209. X
  1210. Xstatic int mygetc()
  1211. X{
  1212. X    static int lastc = 0;
  1213. X
  1214. X    if (lastc == EOF)
  1215. X        return(EOF);
  1216. X    return(lastc = getchar());
  1217. X}
  1218. X
  1219. X
  1220. X#ifdef MSDOS
  1221. Xstatic int leave()
  1222. X{
  1223. X    return(0);
  1224. X}
  1225. X
  1226. Xstatic void cleanup()
  1227. X{
  1228. X    int i;
  1229. X
  1230. X    if (patch.ph_safeid) {
  1231. X        for (i = 0; i < nhandles; i++) {
  1232. X            if (!(handles[i]->h_di->di_flags & DI_CLEANED)) {
  1233. X                sprintf(pathbuf, "%s%s%03d",
  1234. X                    handles[i]->h_name, IDF, handles[i]->h_di->di_did);
  1235. X                if (unlink(pathbuf))
  1236. X                    fprintf(stderr, "Strange, couldn't unlink %s.\n", pathbuf);
  1237. X                handles[i]->h_di->di_flags |= DI_CLEANED;
  1238. X            }
  1239. X        }
  1240. X    }
  1241. X/*
  1242. X    Write device availability: undocumented internal MS-D*S function.
  1243. X    Restore previous value.
  1244. X*/
  1245. X    bdos(0x37, olddevflag, 3);
  1246. X}
  1247. X
  1248. X#endif
  1249. END_OF_FILE
  1250. if test 7214 -ne `wc -c <'mmv.c.2'`; then
  1251.     echo shar: \"'mmv.c.2'\" unpacked with wrong size!
  1252. fi
  1253. # end of 'mmv.c.2'
  1254. fi
  1255. echo shar: End of archive 1 \(of 2\).
  1256. cp /dev/null ark1isdone
  1257. MISSING=""
  1258. for I in 1 2 ; do
  1259.     if test ! -f ark${I}isdone ; then
  1260.     MISSING="${MISSING} ${I}"
  1261.     fi
  1262. done
  1263. if test "${MISSING}" = "" ; then
  1264.     echo You have unpacked both archives.
  1265.     rm -f ark[1-9]isdone
  1266. else
  1267.     echo You still need to unpack the following archives:
  1268.     echo "        " ${MISSING}
  1269. fi
  1270. ##  End of shell archive.
  1271. exit 0
  1272. exit 0 # Just in case...
  1273.